﻿/******************************************************************************
	Cobalt - utility libraries for building XNA games
	Copyright (C) 2008 Philip Djonov

	This program is free software; you can redistribute it and/or modify it
	under the terms of the GNU General Public License as published by the Free
	Software Foundation; either version 2 of the License, or (at your option)
	any later version.

	This program is distributed in the hope that it will be useful, but
	WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
	or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
	for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the
	
		Free Software Foundation, Inc.
		51 Franklin Street, Fifth Floor
		Boston, MA  02110-1301, USA.
******************************************************************************/

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;

namespace Cobalt.Content.Pipeline.Graphics.Imaging
{

	public class SpriteSheetContent : ContentItem
	{

		public Dictionary<string, BitmapContent> Images { get; private set; }
		public List<Texture2DContent> Sheets { get; private set; }
		public Dictionary<string, Texture2DContent> ImageSheets { get; private set; }
		public Dictionary<string, Rectangle> ImageRectangles { get; private set; }

		public SpriteSheetContent()
		{
			Images = new Dictionary<string, BitmapContent>();
			Sheets = new List<Texture2DContent>();
			ImageSheets = new Dictionary<string, Texture2DContent>();
			ImageRectangles = new Dictionary<string, Rectangle>();
		}

	}

	[ContentImporter( ".spritesheet", DisplayName = "Sprite Sheet Importer" )]
	public class SpriteSheetContentImporter : ContentImporter<SpriteSheetContent>
	{
		public override SpriteSheetContent Import( string filename, ContentImporterContext context )
		{
			var ret = new SpriteSheetContent();

			ret.Identity = new ContentIdentity( filename );
			ret.Name = Path.GetFileNameWithoutExtension( filename );

			string baseDir = Path.GetDirectoryName( filename );

			TextureImporter importer = new TextureImporter();

			using( ContentTokenReader reader = ContentTokenReader.FromFile( filename ) )
			{
				for( ; ; )
				{
					string name = reader.ReadToken( TokenReadFlags.RequireLineStart );
					if( name == null )
						break;

					string path = reader.ReadRequiredToken( TokenReadFlags.NoLineBreak );
					path = Path.Combine( baseDir, path );

					context.Logger.LogMessage( "Importing sheet image {0} : {1}", name, path );

					var image = importer.Import( path, context );
					context.AddDependency( path );

					ret.Images.Add( name, image.Faces[0][0] );
				}
			}

			return ret;
		}
	}

	[ContentProcessor( DisplayName = "Sprite Sheet Processor" )]
	public class SpriteSheetContentProcessor : ContentProcessor<SpriteSheetContent, SpriteSheetContent>
	{
		public override SpriteSheetContent Process( SpriteSheetContent input, ContentProcessorContext context )
		{
			var sheet = ImagePacker.Pack( input.Images.Values );

			var tex = new Texture2DContent();
			tex.Mipmaps.Add( sheet.SheetImage );

			input.Sheets.Add( tex );

			foreach( var img in input.Images )
			{
				input.ImageSheets.Add( img.Key, tex );
				input.ImageRectangles.Add( img.Key, sheet.ImagePositions[img.Value] );
			}

			return input;
		}
	}

	[ContentTypeWriter]
	public class SpriteSheetContentWriter : ContentTypeWriter<SpriteSheetContent>
	{
		protected override void Write( ContentWriter output, SpriteSheetContent value )
		{
			output.Write( value.Sheets.Count );
			value.Sheets.ForEach( s => output.WriteRawObject( s ) );

			output.Write( value.ImageSheets.Count );
			foreach( var s in from s in value.ImageSheets.Keys orderby s select s )
			{
				output.Write( s );
				output.Write( value.Sheets.IndexOf( value.ImageSheets[s] ) );
				output.WriteRawObject( value.ImageRectangles[s] );
			}
		}

		public override string GetRuntimeReader( TargetPlatform targetPlatform )
		{
			return Helpers.GetCobaltFrameworkTypeString( "Graphics.SpriteSheetReader" );
		}

		public override string GetRuntimeType( TargetPlatform targetPlatform )
		{
			return Helpers.GetCobaltFrameworkTypeString( "Graphics.SpriteSheet" );
		}
	}

}